{-# LANGUAGE OverloadedStrings, NoMonomorphismRestriction #-}


import Data.Tree
import Data.Text (pack)
import Data.Char (toUpper)
import Data.List
import Data.List.Split
import Text.LaTeX hiding (tex)
import Text.LaTeX.Base.Class
import Text.LaTeX.Base.Syntax


main = do
    file <- readFile "InterfaceCatalog.int"
    --return $ linesToText $ filter (/= "") $ map rstrip $ lines file
    renderFile "InterfaceCatalog.tex" $ linesToText $ filter (/= "") $ map rstrip $ lines file



-- flow
linesToText = toTexList . toInterfaceList . toComponentForest


-- raw
toComponentForest :: [String] -> [(String, [(String, [String])])]
toComponentForest [] = []
toComponentForest (x:xs) = (x, toInterfaceForest $ map (drop 4) is) : (toComponentForest rest)
    where
        (is, rest) = span (isPrefixOf "    ") xs

toInterfaceForest :: [String] -> [(String, [String])]
toInterfaceForest [] = []
toInterfaceForest (x:xs) = (x, map (drop 6) is) : (toInterfaceForest  rest)
    where
        (is, rest) = span (isPrefixOf "    - ") xs

-- Interface
data Interface = Interface {
    name :: String,
    component :: String,
    desc :: String,
    operations :: [Operation]
} deriving (Show)


sortInterface = sortBy (\a b -> compare (go a) (go b) )
    where go x = fmap toUpper $ name x


data Operation = Operation {
    oName :: String,
    oDesc :: String
} deriving (Show)

sortOperation = sortBy (\a b -> compare (go a) (go b) )
    where go x = fmap toUpper $ (words $ oName x)!!1


toInterfaceList :: [(String, [(String, [String])])] -> [Interface]
toInterfaceList xs = sortInterface $ concatMap go xs
    where
        go :: (String, [(String, [String])]) -> [Interface]
        go (par, is) = map (toInterface par) is

toInterface :: String -> (String, [String]) -> Interface
toInterface par (t, os) = Interface a par b (toOperationList os)
    where
        (a,b) = splitToPairSafe $ (splitOn ": " t)

-- not storted
toOperationList :: [String] -> [Operation]
toOperationList x = sortOperation $ map go x
    where
        go = (\(a,b) -> (Operation a b)).split
        split = splitToPairSafe . (splitOn ": ")

splitToPairSafe :: [String] -> (String, String)
splitToPairSafe ab = (abx!!0,abx!!1)
    where abx = ab ++ ["-"]


-- Hatex
toTexList :: [Interface] -> LaTeX
toTexList xs = (section $ raw "Interface Catalog") <> (tex "In this catalog we document the interfaces and methods provided by the components of the system. When no methods are specified, a general description of the interface is given. Interfaces delegated to lower level components are indicated with \\textsc{Provided by}. Interfaces provided by external systems are indicated with \\textsc{External Interface}.") <> (mconcat $ map go xs)
    where 
        go i = subsection (tex $ name i) <> description ((mconcat $ map (\(n,f)-> (item $ Just n) <> (tex $ f i)) [("Provided by",component), ("Semantics",desc)]) <> (oList $ operations i))
        oList :: [Operation] -> LaTeX
        oList [] = mempty
        oList os = (description (mconcat $ map (\(Operation on od) ->  (item $ Just $ texttt (small $ tex on)) <> hfill <> newline <> (tex od)) os))

tex = TeXRaw . pack

-- strip
wschars :: String
wschars = " \t\r\n"

strip :: String -> String
strip = lstrip . rstrip

lstrip :: String -> String
lstrip s = case s of
                  [] -> []
                  (x:xs) -> if elem x wschars
                            then lstrip xs
                            else s

rstrip :: String -> String
rstrip = reverse . lstrip . reverse